﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using TanmiaGrp.Basis;
using TanmiaGrp.Basis.Core;
using TanmiaGrp.GeneralLedger.Domain;
using TanmiaGrp.GeneralLedger.WinApp.Commands;

namespace TanmiaGrp.GeneralLedger.WinApp
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TBusinessObject"></typeparam>
    /// <remarks>
    /// 
    /// Events Table
    /// Name                        Browser             Editor      Description
    /// -----------------------------------------------------------------------
    /// EntitySavedOrDeletedEvent   LISTEN              FIRE
    /// EntityNavigationEvent       DELEGATETO          CALL
    /// BrowserInitializedEvent     FIRE                LISTEN
    /// PageNavigationEvent         FIRE                LISTEN
    /// </remarks>
    public abstract class BaseViewModel<TBusinessObject, TBusinessDomain> : BaseViewModel
        where TBusinessObject : BusinessObject, new()
        where TBusinessDomain : BaseDomain<TBusinessObject, TBusinessDomain>, new()
    {
        /// <summary>
        /// Gets human name of the entity.
        /// </summary>
        public virtual string DisplayEntityName
        {
            get { return typeof(TBusinessObject).Name; }
        }

        /// <summary>
        /// Business Domain object.
        /// </summary>
        public TBusinessDomain BusinessDomain { get; protected set; }

        /// <summary>
        /// Gets the editor URI path.
        /// </summary>
        public Uri EditorView { get; protected set; }

        /// <summary>
        /// Gets the browser URI path.
        /// </summary>
        public Uri BrowserView { get; protected set; }

        /// <summary>
        /// Occurs when EditorViewModel.Entity is saved or deleted at repository.
        /// </summary>
        public Enum EntitySavedOrDeletedEvent { get; set; }

        /// <summary>
        /// Occurs when EditorViewModel navigate to another Entity.
        /// </summary>
        public Enum EntityNavigationEvent { get; set; }

        /// <summary>
        /// Occurs when BrowserViewModel created, and loaded its content.
        /// </summary>
        public Enum BrowserInitializedEvent { get; set; }

        /// <summary>
        /// Occurs when BrowserViewModel navigate to another page of Entities.
        /// </summary>
        public Enum PageNavigationEvent { get; set; }

        /// <summary>
        /// Occurs when <see cref="BaseBrowserViewModel"/> Navigator state is changed.
        /// </summary>
        public Enum BrowserStateChangedEvent { get; set; }

        /// <summary>
        /// Raise <see cref="BaseBrowserViewModel.BrowserStateChangedEvent"/> event.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnBrowserStateChanged(BrowserStateChangedEventArgs e)
        {
            Debug.Assert(e != null, "BrowserStateChangedEventArgs must not be null.");
            Debug.WriteLineIf(BrowserStateChangedEvent == null, "BrowserStateChangedEvent event is not wired to be raised.");

            if (BrowserStateChangedEvent != null)
                BrowserStateChangedEvent.Fire<BrowserStateChangedEventArgs>(e);
        }

        /// <summary>
        /// Raises BaseViewModel.EntitySavedOrDeletedEvent event.
        /// Called to notify BrowserViewModel to refresh itself.
        /// </summary>
        /// <param name="args"></param>
        protected virtual void OnEntitySavedOrDeleted(TBusinessObject bizObj)
        {
            Debug.WriteLineIf(EntitySavedOrDeletedEvent == null, "EntitySavedOrDeletedEvent event is not wired to be raised.");
            Debug.WriteLineIf(bizObj == null, "EntitySavedOrDeletedEvent bizObj is null.");

            if (EntitySavedOrDeletedEvent != null)
                EntitySavedOrDeletedEvent.Fire<TBusinessObject>(bizObj);
        }

        /// <summary>
        /// Calls EntityNavigationEvent
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected virtual BrowserStateChangedEventArgs OnEntityNavigation(NavigationMoveEnum? args)
        {
            Debug.WriteLineIf(EntityNavigationEvent == null, "EntityNavigationEvent event is not wired to be raised.");
            Debug.WriteLineIf(args == null, "EntityNavigationEvent args is null.");

            if (EntityNavigationEvent != null)
                return EntityNavigationEvent.Call<NavigationMoveEnum?, BrowserStateChangedEventArgs>(args);

            return null;
        }

        /// <summary>
        /// Fires BrowserInitializedEvent
        /// </summary>
        /// <param name="isAtFirst"></param>
        /// <param name="isAtLast"></param>
        /// <param name="currentEntity"></param>
        protected virtual void OnBrowserInitialized(bool isAtFirst, bool isAtLast, object currentEntity)
        {
            OnBrowserInitialized(new BrowserStateChangedEventArgs { IsAtFirst = isAtFirst, IsAtLast = isAtLast, CurrentEntity = currentEntity });
        }

        /// <summary>
        /// Fires BrowserInitializedEvent
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnBrowserInitialized(BrowserStateChangedEventArgs e)
        {
            Debug.Assert(e != null, "RecordNavigationEventArgs e must not be null.");
            Debug.WriteLineIf(EntityNavigationEvent == null, "EntityNavigationEvent event is not wired to be raised.");

            if (BrowserInitializedEvent != null)
                BrowserInitializedEvent.Fire(e);
        }

        /// <summary>
        /// Fires PageNavigationEvent.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnPageNavigation(NavigationMoveEnum? e)
        {
            Debug.Assert(e != null, "NavigationMoveEnum e must not be null.");
            Debug.WriteLineIf(PageNavigationEvent == null, "PageNavigationEvent event is not wired to be raised.");

            if (PageNavigationEvent != null)
                PageNavigationEvent.Fire<NavigationMoveEnum?>(e);
        }
    }

    public abstract class BaseViewModel : NotificationObject
    {
        /// <summary>
        /// Gets the command to invoke when (Close) button is pressed.
        /// </summary>
        public ICommand CloseCommand { get; protected set; }

        /// <summary>
        /// Execute close logic of current view.
        /// </summary>
        public Action<object> Close { get; set; }

        /// <summary>
        /// Occurs when ViewModel request to change current view in workspace.
        /// </summary>
        public Enum UpdateCurrentViewEvent { get; set; }

        public BaseViewModel()
        {
            CloseCommand = new DelegateCommand<object>(OnCloseHandler);
            UpdateCurrentViewEvent = Events.UpdateCurrentView;
        }

        /// <summary>
        /// Called when <see cref="CloseCommand"/> is executed.
        /// </summary>
        protected abstract void OnCloseHandler(object sender);

        /// <summary>
        /// Wire the events to its event handlers.
        /// </summary>
        protected virtual void Initialize() { }
    }
}